/*
 / _____)             _              | |
( (____  _____ ____ _| |_ _____  ____| |__
 \____ \| ___ |    (_   _) ___ |/ ___)  _ \
 _____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
    (C)2013 Semtech

Description: SX1276 driver specific target board functions implementation

License: Revised BSD License, see LICENSE.TXT file include in the project

Maintainer: Miguel Luis and Gregory Cristian
*/
#include "radio.h"
#include "sx1276.h"
#include "sx1276-hal.h"
#include "event_groups.h"

#define LORA_SPI	hspi1

/*!
 * Flag used to set the RF switch control pins in low power mode when the radio is not active.
 */
static bool RadioIsActive = false;

/*!
 * Radio driver structure initialization
 */

TimerHandle_t task_dio=NULL;
EventGroupHandle_t event_dio=NULL;
static SemaphoreHandle_t mutex_lora;


static gpio_irq_handler io0_irq_handler=NULL;
static gpio_irq_handler io1_irq_handler=NULL;
static gpio_irq_handler io2_irq_handler=NULL;
static gpio_irq_handler io3_irq_handler=NULL;


void lora_gpio_write(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin,  uint32_t value)
{
  HAL_GPIO_WritePin(GPIOx, GPIO_Pin, (GPIO_PinState) value);
}

static uint16_t lora_spi_inout(uint16_t txData)
{
  uint16_t rxData ;
  HAL_SPI_TransmitReceive(&LORA_SPI, (uint8_t *) &txData, (uint8_t *) &rxData, 1, 100);
  return rxData;
}

static void lora_dio_task(void *param)
{

    uint32_t value;
    while(1)
    {
        //value=xEventGroupWaitBits(event_dio,LDIO0_Pin|LDIO1_Pin|LDIO2_Pin|LDIO3_Pin,pdTRUE,pdFALSE,portMAX_DELAY);
        xTaskNotifyWait( 0x00, 0XFFFFFFFFUL, &value, portMAX_DELAY );
        if(value&LDIO0_Pin)
        {
            io0_irq_handler();    
        }
        if(value&LDIO1_Pin)
        {
            io1_irq_handler();    
        }
        if(value&LDIO2_Pin)
        {
            io2_irq_handler();   
        }
        if(value&LDIO3_Pin)
        {
            io3_irq_handler();
        }
    }    
}

void lora_writebuf( uint8_t addr, uint8_t *buffer, uint8_t size )
{
    uint8_t i;
    xSemaphoreTake(mutex_lora,portMAX_DELAY);

    lora_gpio_write( LCS_GPIO_Port, LCS_Pin, 0 );

    lora_spi_inout( addr | 0x80 );
    for( i = 0; i < size; i++ )
    {
        lora_spi_inout( buffer[i] );
    }

    lora_gpio_write( LCS_GPIO_Port, LCS_Pin, 1 );

    xSemaphoreGive(mutex_lora);
}

void lora_readbuf( uint8_t addr, uint8_t *buffer, uint8_t size )
{
    uint8_t i;
    xSemaphoreTake(mutex_lora,portMAX_DELAY);

    lora_gpio_write( LCS_GPIO_Port, LCS_Pin, 0 );

    lora_spi_inout( addr & 0x7F );

    for( i = 0; i < size; i++ )
    {
        buffer[i] = lora_spi_inout( 0 );
    }

    lora_gpio_write( LCS_GPIO_Port, LCS_Pin, 1 );
    
    xSemaphoreGive(mutex_lora);
}


void lora_gpio_irq_handler()
{
    BaseType_t higherTask = pdFALSE;
    if(__HAL_GPIO_EXTI_GET_IT(LDIO0_Pin) != 0x00u)
    {
        __HAL_GPIO_EXTI_CLEAR_IT(LDIO0_Pin);
        if(task_dio!=NULL)xTaskNotifyFromISR(task_dio,LDIO0_Pin,eSetBits,&higherTask);
        //xEventGroupSetBitsFromISR(event_dio,LDIO0_Pin,&higherTask);
    }
    else if(__HAL_GPIO_EXTI_GET_IT(LDIO1_Pin) != 0x00u)
    {
        __HAL_GPIO_EXTI_CLEAR_IT(LDIO1_Pin);
        if(task_dio!=NULL)xTaskNotifyFromISR(task_dio,LDIO1_Pin,eSetBits,&higherTask);
        //xEventGroupSetBitsFromISR(event_dio,LDIO1_Pin,&higherTask);
    }
    else if(__HAL_GPIO_EXTI_GET_IT(LDIO2_Pin) != 0x00u)
    {
        __HAL_GPIO_EXTI_CLEAR_IT(LDIO2_Pin);
        if(task_dio!=NULL)xTaskNotifyFromISR(task_dio,LDIO2_Pin,eSetBits,&higherTask);
        //xEventGroupSetBitsFromISR(event_dio,LDIO2_Pin,&higherTask);
    }
    else if(__HAL_GPIO_EXTI_GET_IT(LDIO3_Pin) != 0x00u)
    {
        __HAL_GPIO_EXTI_CLEAR_IT(LDIO3_Pin);
        if(task_dio!=NULL)xTaskNotifyFromISR(task_dio,LDIO3_Pin,eSetBits,&higherTask);
        //xEventGroupSetBitsFromISR(event_dio,LDIO3_Pin,&higherTask);
    }
    portYIELD_FROM_ISR(higherTask);

}

void lora_delay_ms(uint32_t ms)
{
	vTaskDelay(ms);
}
TimerEvent_t lora_timer_init( const char *timerName, const TickType_t period, TimerCallbackFunction_t callback )
{
	return xTimerCreate(timerName, period,pdFALSE,NULL,callback);
}
void lora_timer_set_value(TimerEvent_t xTimer, TickType_t newPeriod)
{
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	if(__get_IPSR())  //in irq
	{
		xTimerChangePeriodFromISR( xTimer, newPeriod,&xHigherPriorityTaskWoken );
	}
	else xTimerChangePeriod(xTimer,newPeriod,portMAX_DELAY);
}

void lora_timer_start(TimerEvent_t xTimer)
{
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	if(__get_IPSR())  //in irq
	{
		xTimerStartFromISR( xTimer, &xHigherPriorityTaskWoken );
	}
	else xTimerStart(xTimer,portMAX_DELAY );
}

void lora_timer_stop(TimerEvent_t xTimer)
{
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	if(__get_IPSR())  //in irq
	{
		xTimerStopFromISR( xTimer, &xHigherPriorityTaskWoken );
	}
	xTimerStop(xTimer,portMAX_DELAY );
}


void SX1276IoInit( DioIrqHandler **irqHandlers )
{
    //event_dio=xEventGroupCreate();
    
    /* create lora mutex ,for spi  */
    mutex_lora=xSemaphoreCreateMutex();
    xSemaphoreGive(mutex_lora);
    /* create dio irq task,The IO interrupt signal is processed in the task  */
    xTaskCreate(lora_dio_task, "lora_dio_task", 128, NULL, 2, &task_dio);
    
    /* Bind the interrupt service function */
    io0_irq_handler=irqHandlers[0];
    io1_irq_handler=irqHandlers[1];
    io2_irq_handler=irqHandlers[2];
    io3_irq_handler=irqHandlers[3];
}

void SX1276IoDeInit( void )
{

}

uint8_t SX1276GetPaSelect( uint32_t channel )
{
    if( channel < RF_MID_BAND_THRESH )
    {
        return RF_PACONFIG_PASELECT_PABOOST;
    }
    else
    {
        return RF_PACONFIG_PASELECT_RFO;
    }
}

void SX1276SetAntSwLowPower( bool status )
{
    if( RadioIsActive != status )
    {
        RadioIsActive = status;
    
        if( status == false )
        {
            SX1276AntSwInit( );
        }
        else
        {
            SX1276AntSwDeInit( );
        }
    }
}

void SX1276AntSwInit( void )
{

}

void SX1276AntSwDeInit( void )
{

}

void SX1276SetAntSw( uint8_t rxTx )
{

}
